"""
风险报告生成器

提供投资组合和策略的风险分析报告，包括市场风险、信用风险、流动性风险等。
"""

from typing import Dict, List, Optional, Any, Union
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from decimal import Decimal
from enum import Enum
import math

from .report_generator import ReportGenerator, ReportConfig, ReportFormat, ReportType, ReportData


class RiskType(Enum):
    """风险类型"""
    MARKET = "market"  # 市场风险
    CREDIT = "credit"  # 信用风险
    LIQUIDITY = "liquidity"  # 流动性风险
    OPERATIONAL = "operational"  # 操作风险
    CONCENTRATION = "concentration"  # 集中度风险
    LEVERAGE = "leverage"  # 杠杆风险


@dataclass
class RiskMetrics:
    """风险指标数据类"""
    # 市场风险指标
    var_1d: Decimal = Decimal('0')  # 1日VaR
    var_5d: Decimal = Decimal('0')  # 5日VaR
    var_10d: Decimal = Decimal('0')  # 10日VaR
    cvar_1d: Decimal = Decimal('0')  # 1日CVaR
    cvar_5d: Decimal = Decimal('0')  # 5日CVaR
    cvar_10d: Decimal = Decimal('0')  # 10日CVaR
    
    # 波动率指标
    realized_volatility: Decimal = Decimal('0')  # 已实现波动率
    implied_volatility: Optional[Decimal] = None  # 隐含波动率
    volatility_skew: Decimal = Decimal('0')  # 波动率偏斜
    
    # 相关性指标
    portfolio_correlation: Decimal = Decimal('0')  # 组合内相关性
    market_correlation: Decimal = Decimal('0')  # 与市场相关性
    sector_correlation: Dict[str, Decimal] = field(default_factory=dict)  # 行业相关性
    
    # 集中度风险
    concentration_ratio: Decimal = Decimal('0')  # 集中度比率
    herfindahl_index: Decimal = Decimal('0')  # 赫芬达尔指数
    max_position_weight: Decimal = Decimal('0')  # 最大持仓权重
    top5_concentration: Decimal = Decimal('0')  # 前5大持仓集中度
    
    # 流动性风险
    liquidity_score: Decimal = Decimal('0')  # 流动性评分
    avg_daily_volume: Decimal = Decimal('0')  # 平均日成交量
    bid_ask_spread: Decimal = Decimal('0')  # 买卖价差
    market_impact: Decimal = Decimal('0')  # 市场冲击成本
    
    # 杠杆风险
    leverage_ratio: Decimal = Decimal('0')  # 杠杆比率
    gross_exposure: Decimal = Decimal('0')  # 总敞口
    net_exposure: Decimal = Decimal('0')  # 净敞口
    
    # 压力测试结果
    stress_test_results: Dict[str, Decimal] = field(default_factory=dict)
    
    # 时间相关
    calculation_date: datetime = field(default_factory=datetime.now)
    lookback_period: int = 252  # 回望期（交易日）


@dataclass
class RiskScenario:
    """风险情景"""
    name: str
    description: str
    market_shock: Dict[str, Decimal] = field(default_factory=dict)  # 市场冲击
    expected_loss: Decimal = Decimal('0')  # 预期损失
    probability: Decimal = Decimal('0')  # 发生概率
    impact_level: str = "medium"  # 影响程度: low, medium, high, extreme


@dataclass
class RiskData:
    """风险数据"""
    portfolio_id: str
    strategy_id: Optional[str] = None
    
    # 持仓数据
    positions: Dict[str, Decimal] = field(default_factory=dict)  # 持仓权重
    market_values: Dict[str, Decimal] = field(default_factory=dict)  # 市值
    
    # 价格数据
    price_history: Dict[str, List[Decimal]] = field(default_factory=dict)  # 价格历史
    return_history: Dict[str, List[Decimal]] = field(default_factory=dict)  # 收益率历史
    
    # 市场数据
    market_data: Dict[str, Any] = field(default_factory=dict)  # 市场数据
    benchmark_data: Dict[str, List[Decimal]] = field(default_factory=dict)  # 基准数据
    
    # 计算得出的指标
    metrics: RiskMetrics = field(default_factory=RiskMetrics)
    
    # 风险情景
    scenarios: List[RiskScenario] = field(default_factory=list)
    
    # 风险限额
    risk_limits: Dict[str, Decimal] = field(default_factory=dict)
    
    # 风险预警
    risk_alerts: List[Dict[str, Any]] = field(default_factory=list)


class RiskReportGenerator(ReportGenerator):
    """风险报告生成器"""
    
    def __init__(self, config: Optional[ReportConfig] = None):
        """
        初始化风险报告生成器
        
        Args:
            config: 报告配置
        """
        super().__init__(config or ReportConfig(
            report_type=ReportType.RISK,
            format=ReportFormat.JSON,
            title="风险分析报告"
        ))
        self.confidence_levels = [0.95, 0.99]  # VaR置信水平
        self.time_horizons = [1, 5, 10]  # 时间范围（天）
    
    def collect_data(self, **kwargs) -> ReportData:
        """收集报告数据"""
        risk_data = kwargs.get('risk_data')
        if not risk_data:
            raise ValueError("需要提供risk_data参数")
        
        # 计算风险指标
        self._calculate_risk_metrics(risk_data)
        
        # 创建报告数据
        report_data = ReportData(
            title=self.config.title,
            subtitle=f"组合: {risk_data.portfolio_id}",
            summary=self._create_risk_summary(risk_data),
            metadata={
                "portfolio_id": risk_data.portfolio_id,
                "strategy_id": risk_data.strategy_id,
                "calculation_date": risk_data.metrics.calculation_date.isoformat()
            }
        )
        
        # 添加各个章节
        sections = [
            self.create_section("风险概览", self._create_risk_overview(risk_data)),
            self.create_section("市场风险", self._create_market_risk_analysis(risk_data)),
            self.create_section("集中度风险", self._create_concentration_analysis(risk_data)),
            self.create_section("流动性风险", self._create_liquidity_analysis(risk_data)),
            self.create_section("压力测试", self._create_stress_test_analysis(risk_data)),
            self.create_section("风险限额监控", self._create_risk_limits_monitoring(risk_data)),
            self.create_section("风险预警", self._create_risk_alerts(risk_data))
        ]
        
        # 添加表格
        tables = [
            self._create_var_table(risk_data),
            self._create_concentration_table(risk_data),
            self._create_stress_test_table(risk_data)
        ]
        
        report_data.sections = sections
        report_data.tables = tables
        return report_data
    
    def generate_content(self, data: ReportData) -> str:
        """生成报告内容"""
        return self.generate_to_json(data)
    
    def generate_risk_report(
        self,
        risk_data: RiskData,
        format_type: ReportFormat = ReportFormat.JSON,
        save_path: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        生成风险报告
        
        Args:
            risk_data: 风险数据
            format_type: 报告格式
            save_path: 保存路径
            
        Returns:
            报告数据
        """
        # 使用基类的generate_report方法
        self.config.format = format_type
        if save_path:
            self.config.output_path = save_path
        
        content = self.generate_report(risk_data=risk_data)
        
        # 返回原始数据用于进一步处理
        return {
            "report_content": content,
            "risk_data": risk_data,
            "metrics": risk_data.metrics
        }
    
    def _calculate_risk_metrics(self, data: RiskData) -> None:
        """计算风险指标"""
        # 计算VaR和CVaR
        self._calculate_var_cvar(data)
        
        # 计算波动率指标
        self._calculate_volatility_metrics(data)
        
        # 计算相关性指标
        self._calculate_correlation_metrics(data)
        
        # 计算集中度风险
        self._calculate_concentration_risk(data)
        
        # 计算流动性风险
        self._calculate_liquidity_risk(data)
        
        # 计算杠杆风险
        self._calculate_leverage_risk(data)
        
        # 执行压力测试
        self._perform_stress_tests(data)
    
    def _calculate_var_cvar(self, data: RiskData) -> None:
        """计算VaR和CVaR"""
        if not data.return_history:
            return
        
        # 合并所有收益率数据
        all_returns = []
        for returns in data.return_history.values():
            all_returns.extend([float(r) for r in returns])
        
        if not all_returns:
            return
        
        sorted_returns = sorted(all_returns)
        n = len(sorted_returns)
        
        # 计算不同时间范围的VaR和CVaR
        for days in self.time_horizons:
            scaling_factor = math.sqrt(days)
            
            for confidence in self.confidence_levels:
                alpha = 1 - confidence
                var_index = int(n * alpha)
                
                if var_index < n:
                    var_value = abs(sorted_returns[var_index]) * scaling_factor
                    
                    # CVaR计算
                    tail_returns = sorted_returns[:var_index+1]
                    cvar_value = abs(sum(tail_returns) / len(tail_returns)) * scaling_factor if tail_returns else 0
                    
                    # 存储结果
                    if days == 1 and confidence == 0.95:
                        data.metrics.var_1d = Decimal(str(var_value))
                        data.metrics.cvar_1d = Decimal(str(cvar_value))
                    elif days == 5 and confidence == 0.95:
                        data.metrics.var_5d = Decimal(str(var_value))
                        data.metrics.cvar_5d = Decimal(str(cvar_value))
                    elif days == 10 and confidence == 0.95:
                        data.metrics.var_10d = Decimal(str(var_value))
                        data.metrics.cvar_10d = Decimal(str(cvar_value))
    
    def _calculate_volatility_metrics(self, data: RiskData) -> None:
        """计算波动率指标"""
        if not data.return_history:
            return
        
        # 计算已实现波动率
        all_returns = []
        for returns in data.return_history.values():
            all_returns.extend([float(r) for r in returns])
        
        if len(all_returns) > 1:
            mean_return = sum(all_returns) / len(all_returns)
            variance = sum((r - mean_return) ** 2 for r in all_returns) / (len(all_returns) - 1)
            data.metrics.realized_volatility = Decimal(str(math.sqrt(variance) * math.sqrt(252)))
    
    def _calculate_correlation_metrics(self, data: RiskData) -> None:
        """计算相关性指标"""
        if len(data.return_history) < 2:
            return
        
        # 计算组合内资产相关性
        assets = list(data.return_history.keys())
        correlations = []
        
        for i in range(len(assets)):
            for j in range(i+1, len(assets)):
                asset1_returns = [float(r) for r in data.return_history[assets[i]]]
                asset2_returns = [float(r) for r in data.return_history[assets[j]]]
                
                if len(asset1_returns) == len(asset2_returns) and len(asset1_returns) > 1:
                    corr = self._calculate_correlation(asset1_returns, asset2_returns)
                    correlations.append(corr)
        
        if correlations:
            data.metrics.portfolio_correlation = Decimal(str(sum(correlations) / len(correlations)))
    
    def _calculate_correlation(self, x: List[float], y: List[float]) -> float:
        """计算两个序列的相关系数"""
        if len(x) != len(y) or len(x) < 2:
            return 0.0
        
        n = len(x)
        mean_x = sum(x) / n
        mean_y = sum(y) / n
        
        numerator = sum((x[i] - mean_x) * (y[i] - mean_y) for i in range(n))
        
        sum_sq_x = sum((x[i] - mean_x) ** 2 for i in range(n))
        sum_sq_y = sum((y[i] - mean_y) ** 2 for i in range(n))
        
        denominator = math.sqrt(sum_sq_x * sum_sq_y)
        
        return numerator / denominator if denominator != 0 else 0.0
    
    def _calculate_concentration_risk(self, data: RiskData) -> None:
        """计算集中度风险"""
        if not data.positions:
            return
        
        weights = [float(w) for w in data.positions.values()]
        total_weight = sum(weights)
        
        if total_weight > 0:
            # 标准化权重
            normalized_weights = [w / total_weight for w in weights]
            
            # 最大持仓权重
            data.metrics.max_position_weight = Decimal(str(max(normalized_weights)))
            
            # 前5大持仓集中度
            sorted_weights = sorted(normalized_weights, reverse=True)
            top5_weights = sorted_weights[:5]
            data.metrics.top5_concentration = Decimal(str(sum(top5_weights)))
            
            # 赫芬达尔指数
            hhi = sum(w ** 2 for w in normalized_weights)
            data.metrics.herfindahl_index = Decimal(str(hhi))
            
            # 集中度比率（前3大持仓）
            top3_weights = sorted_weights[:3]
            data.metrics.concentration_ratio = Decimal(str(sum(top3_weights)))
    
    def _calculate_liquidity_risk(self, data: RiskData) -> None:
        """计算流动性风险"""
        # 这里可以根据实际的市场数据计算流动性指标
        # 目前使用模拟数据
        data.metrics.liquidity_score = Decimal('0.75')  # 流动性评分 0-1
        data.metrics.avg_daily_volume = Decimal('1000000')  # 平均日成交量
        data.metrics.bid_ask_spread = Decimal('0.001')  # 买卖价差
        data.metrics.market_impact = Decimal('0.002')  # 市场冲击成本
    
    def _calculate_leverage_risk(self, data: RiskData) -> None:
        """计算杠杆风险"""
        if not data.market_values:
            return
        
        total_long = sum((max(Decimal('0'), v) for v in data.market_values.values()), Decimal('0'))
        total_short = sum((min(Decimal('0'), v) for v in data.market_values.values()), Decimal('0'))
        
        data.metrics.gross_exposure = total_long + (total_short * Decimal('-1') if total_short < 0 else total_short)
        data.metrics.net_exposure = total_long + total_short
        
        if data.metrics.net_exposure != 0:
            data.metrics.leverage_ratio = data.metrics.gross_exposure / abs(data.metrics.net_exposure)
    
    def _perform_stress_tests(self, data: RiskData) -> None:
        """执行压力测试"""
        # 定义压力测试情景
        stress_scenarios = [
            {"name": "市场下跌10%", "shock": -0.10},
            {"name": "市场下跌20%", "shock": -0.20},
            {"name": "波动率上升50%", "shock": -0.15},
            {"name": "流动性危机", "shock": -0.25}
        ]
        
        for scenario in stress_scenarios:
            # 简化的压力测试计算
            portfolio_value = sum(data.market_values.values()) if data.market_values else Decimal('0')
            stress_loss = portfolio_value * Decimal(str(abs(scenario["shock"])))
            data.metrics.stress_test_results[scenario["name"]] = stress_loss
    
    def _create_risk_summary(self, data: RiskData) -> Dict[str, Any]:
        """创建风险摘要"""
        metrics = data.metrics
        
        return {
            "关键风险指标": {
                "1日VaR (95%)": f"{float(metrics.var_1d):.2%}",
                "10日VaR (95%)": f"{float(metrics.var_10d):.2%}",
                "已实现波动率": f"{float(metrics.realized_volatility):.2%}",
                "最大持仓权重": f"{float(metrics.max_position_weight):.2%}",
                "集中度比率": f"{float(metrics.concentration_ratio):.2%}",
                "杠杆比率": f"{float(metrics.leverage_ratio):.2f}"
            },
            "风险等级": self._assess_risk_level(data),
            "主要风险点": self._identify_key_risks(data)
        }
    
    def _assess_risk_level(self, data: RiskData) -> str:
        """评估风险等级"""
        metrics = data.metrics
        
        # 简化的风险等级评估
        risk_score = 0
        
        if metrics.var_1d > Decimal('0.02'):  # 2%
            risk_score += 2
        elif metrics.var_1d > Decimal('0.01'):  # 1%
            risk_score += 1
        
        if metrics.concentration_ratio > Decimal('0.5'):  # 50%
            risk_score += 2
        elif metrics.concentration_ratio > Decimal('0.3'):  # 30%
            risk_score += 1
        
        if metrics.leverage_ratio > Decimal('3'):
            risk_score += 2
        elif metrics.leverage_ratio > Decimal('2'):
            risk_score += 1
        
        if risk_score >= 4:
            return "高风险"
        elif risk_score >= 2:
            return "中等风险"
        else:
            return "低风险"
    
    def _identify_key_risks(self, data: RiskData) -> List[str]:
        """识别主要风险点"""
        risks = []
        metrics = data.metrics
        
        if metrics.concentration_ratio > Decimal('0.4'):
            risks.append("持仓集中度过高")
        
        if metrics.var_1d > Decimal('0.02'):
            risks.append("市场风险较大")
        
        if metrics.leverage_ratio > Decimal('2.5'):
            risks.append("杠杆水平偏高")
        
        if metrics.liquidity_score < Decimal('0.5'):
            risks.append("流动性风险")
        
        return risks if risks else ["风险水平正常"]
    
    def _create_risk_overview(self, data: RiskData) -> Dict[str, Any]:
        """创建风险概览"""
        metrics = data.metrics
        
        return {
            "VaR指标": {
                "1日VaR": float(metrics.var_1d),
                "5日VaR": float(metrics.var_5d),
                "10日VaR": float(metrics.var_10d)
            },
            "波动率指标": {
                "已实现波动率": float(metrics.realized_volatility),
                "隐含波动率": float(metrics.implied_volatility) if metrics.implied_volatility else None
            },
            "相关性指标": {
                "组合内相关性": float(metrics.portfolio_correlation),
                "市场相关性": float(metrics.market_correlation)
            }
        }
    
    def _create_market_risk_analysis(self, data: RiskData) -> Dict[str, Any]:
        """创建市场风险分析"""
        return {
            "VaR分析": {
                "1日VaR (95%)": float(data.metrics.var_1d),
                "1日CVaR (95%)": float(data.metrics.cvar_1d),
                "10日VaR (95%)": float(data.metrics.var_10d),
                "10日CVaR (95%)": float(data.metrics.cvar_10d)
            },
            "波动率分析": {
                "已实现波动率": float(data.metrics.realized_volatility),
                "波动率偏斜": float(data.metrics.volatility_skew)
            },
            "敏感性分析": "需要具体的希腊字母计算"
        }
    
    def _create_concentration_analysis(self, data: RiskData) -> Dict[str, Any]:
        """创建集中度分析"""
        return {
            "持仓集中度": {
                "最大持仓权重": float(data.metrics.max_position_weight),
                "前5大持仓集中度": float(data.metrics.top5_concentration),
                "集中度比率": float(data.metrics.concentration_ratio),
                "赫芬达尔指数": float(data.metrics.herfindahl_index)
            },
            "行业集中度": "需要行业分类数据",
            "地区集中度": "需要地区分类数据"
        }
    
    def _create_liquidity_analysis(self, data: RiskData) -> Dict[str, Any]:
        """创建流动性分析"""
        return {
            "流动性指标": {
                "流动性评分": float(data.metrics.liquidity_score),
                "平均日成交量": float(data.metrics.avg_daily_volume),
                "买卖价差": float(data.metrics.bid_ask_spread),
                "市场冲击成本": float(data.metrics.market_impact)
            },
            "流动性风险评估": "基于历史数据的流动性分析"
        }
    
    def _create_stress_test_analysis(self, data: RiskData) -> Dict[str, Any]:
        """创建压力测试分析"""
        return {
            "压力测试结果": {
                scenario: float(loss) for scenario, loss in data.metrics.stress_test_results.items()
            },
            "极端情景分析": "基于历史极端事件的分析"
        }
    
    def _create_risk_limits_monitoring(self, data: RiskData) -> Dict[str, Any]:
        """创建风险限额监控"""
        return {
            "风险限额": data.risk_limits,
            "当前使用情况": "需要实时监控数据",
            "超限预警": "无超限情况" if not data.risk_alerts else f"发现{len(data.risk_alerts)}个预警"
        }
    
    def _create_risk_alerts(self, data: RiskData) -> Dict[str, Any]:
        """创建风险预警"""
        return {
            "当前预警": data.risk_alerts,
            "预警统计": {
                "总数": len(data.risk_alerts),
                "高级别": len([alert for alert in data.risk_alerts if alert.get("level") == "high"]),
                "中级别": len([alert for alert in data.risk_alerts if alert.get("level") == "medium"]),
                "低级别": len([alert for alert in data.risk_alerts if alert.get("level") == "low"])
            }
        }
    
    def _create_var_table(self, data: RiskData) -> Dict[str, Any]:
        """创建VaR表格"""
        headers = ["时间范围", "95% VaR", "95% CVaR", "99% VaR", "99% CVaR"]
        rows = [
            ["1日", f"{float(data.metrics.var_1d):.2%}", f"{float(data.metrics.cvar_1d):.2%}", "N/A", "N/A"],
            ["5日", f"{float(data.metrics.var_5d):.2%}", f"{float(data.metrics.cvar_5d):.2%}", "N/A", "N/A"],
            ["10日", f"{float(data.metrics.var_10d):.2%}", f"{float(data.metrics.cvar_10d):.2%}", "N/A", "N/A"]
        ]
        
        return self.create_table("风险价值(VaR)分析", headers, rows)
    
    def _create_concentration_table(self, data: RiskData) -> Dict[str, Any]:
        """创建集中度表格"""
        headers = ["指标", "数值", "风险等级"]
        rows = [
            ["最大持仓权重", f"{float(data.metrics.max_position_weight):.2%}", 
             "高" if data.metrics.max_position_weight > Decimal('0.2') else "中" if data.metrics.max_position_weight > Decimal('0.1') else "低"],
            ["前5大集中度", f"{float(data.metrics.top5_concentration):.2%}",
             "高" if data.metrics.top5_concentration > Decimal('0.6') else "中" if data.metrics.top5_concentration > Decimal('0.4') else "低"],
            ["赫芬达尔指数", f"{float(data.metrics.herfindahl_index):.4f}",
             "高" if data.metrics.herfindahl_index > Decimal('0.2') else "中" if data.metrics.herfindahl_index > Decimal('0.1') else "低"]
        ]
        
        return self.create_table("集中度风险分析", headers, rows)
    
    def _create_stress_test_table(self, data: RiskData) -> Dict[str, Any]:
        """创建压力测试表格"""
        headers = ["压力情景", "预期损失", "损失比例"]
        rows = []
        
        total_value = sum(data.market_values.values()) if data.market_values else Decimal('1')
        
        for scenario, loss in data.metrics.stress_test_results.items():
            loss_pct = (loss / total_value) if total_value != 0 else Decimal('0')
            rows.append([
                scenario,
                f"¥{float(loss):,.2f}",
                f"{float(loss_pct):.2%}"
            ])
        
        return self.create_table("压力测试结果", headers, rows)